"""
逻辑回归 on keras & sklearn
"""
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras import metrics
from utils.plot_graph import keras_plot_model
from utils.model_info import ModelFitPredict


def load_data(valid_ratio=0.2, test_ratio=0.2):
    """

    :param valid_ratio:
    :param test_ratio:
    :return:
    """
    x, y = datasets.load_digits(return_X_y=True)
    x = StandardScaler().fit_transform(x)
    # 是否大于4
    y = (y > 4).astype(np.int)

    valid_size = int(len(x) * valid_ratio)
    test_size = int(len(x) * test_ratio)
    x_test = x[-test_size:]
    y_test = y[-test_size:]

    x_train, x_valid, y_train, y_valid = \
        train_test_split(x[: -test_size], y[: -test_size],
                         train_size=len(x) - valid_size - test_size,
                         test_size=valid_size)
    return x_train, x_valid, x_test, y_train, y_valid, y_test


def sklearn_lr(x_train, y_train, x_test, y_test):
    """

    :param x_train:
    :param y_train:
    :param x_test:
    :param y_test:
    :return:
    """
    # clf = LogisticRegression(penalty='l1', tol=0.01, solver='saga')
    clf = LogisticRegression()
    clf.fit(x_train, y_train)

    clf_scores = clf.score(x_test, y_test)

    pred = clf.predict(x_test)
    # keras自带准确率计算
    acc = metrics.BinaryAccuracy()
    acc.update_state(y_pred=pred, y_true=y_test)

    # 准确率自己计算
    scores = np.mean(pred - y_test == 0)

    print('sklearn\nclf_scores: {}, keras scores: {}, my scores: {}'.
          format(clf_scores, acc.result(), scores))


def build_model(input_dim):
    """
    :param input_dim:
    :return:
    """
    model = Sequential()

    # plot_model看不出来activation
    # model.add(Dense(units=1, input_dim=input_dim, activation='sigmoid'))
    model.add(Dense(units=1, input_dim=input_dim))
    model.add(Activation('sigmoid'))

    model.compile(optimizer='sgd', loss='binary_crossentropy', metrics=['acc'])
    return model


def logistic_run(workers):
    """
    主程序
    :return:
    """
    pic_path = '../pic/logsitic_r'
    model_name = '逻辑回归'

    x_train, x_valid, x_test, y_train, y_valid, y_test = load_data()

    input_dim = 1 if len(x_train.shape) == 1 else x_train.shape[1]

    # sklearn lr
    sklearn_lr(x_train=x_train, y_train=y_train, x_test=x_test, y_test=y_test)

    print('*' * 100)

    # keras
    model = build_model(input_dim=input_dim)

    # plot model
    keras_plot_model(model=model, pic='{}/逻辑回归模型.png'.format(pic_path))

    fit_predict = ModelFitPredict(model=model,
                                  train_x=x_train, train_y=y_train,
                                  valid_x=x_valid, valid_y=y_valid,
                                  test_x=x_test, test_y=y_test,
                                  epochs=20,
                                  model_name=model_name,
                                  pic_path=pic_path,
                                  batch_size=64,
                                  workers=workers)

    fit_predict.predict(func=metrics.BinaryAccuracy)
